package cn.wen.bases.dao.hibernate;

import java.io.Serializable;

import java.util.Collection;
import java.util.List;

import org.apache.log4j.Logger;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

/**
 * Title：Hibernate Dao的基类
 * <p>
 * Description：
 * <p>
 * Copyright：Copyright (c) 2010-2012
 * 
 * @author <a href="mailto:ct_wen@qq.com">ctwen</a>, 温承瑭
 * @version Revision：1.0 Date：2010/7/21 Description：初完成。
 *          <p>
 */
public class BaseDao<T> extends HibernateDaoSupport implements IBaseDao<T> {

    /**
     * 作为默认使用类型
     * 
     * @param clz 实体Dao的实体类型
     */
    protected BaseDao(Class<T> clz) {
	super();
	this.entityClass = clz;
	this.hqlPrefix += entityClass.getName() + " as model";
    }

    /**
     * 获取本泛型类的第一参数类型
     */
    /*
     * private void getEntityClass() { if (entityClass == null) { entityClass = (Class<T>) ((ParameterizedType) getClass()
     * .getGenericSuperclass()).getActualTypeArguments()[0]; } }
     */

    private Logger log = Logger.getLogger(BaseDao.class);

    private Class<T> entityClass;

    /**
     * HQL语句的前缀
     */
    protected String hqlPrefix = "from ";

    @Override
    public void persist(T t) {
	try {
	    this.getHibernateTemplate().persist(t);
	}
	catch (Exception e) {
	    log.error(e.getMessage());
	    throw new RuntimeException(e.getMessage());
	}
    }

    @Override
    public void save(T t) {
	try {
	    this.getHibernateTemplate().save(t);
	}
	catch (Exception e) {
	    log.error(e.getMessage());
	    throw new RuntimeException(e.getMessage());
	}
    }

    @Override
    public void saveOrUpdate(T t) {
	try {
	    this.getHibernateTemplate().saveOrUpdate(t);
	}
	catch (Exception e) {
	    log.error(e.getMessage());
	    throw new RuntimeException(e.getMessage());
	}
    }

    @Override
    public void saveOrUpdateAll(Collection t) {
	try {
	    this.getHibernateTemplate().saveOrUpdateAll(t);
	}
	catch (Exception e) {
	    log.error(e.getMessage());
	    throw new RuntimeException(e.getMessage());
	}
    }

    @Override
    public void update(T t) {
	try {
	    this.getHibernateTemplate().update(t);
	}
	catch (Exception e) {
	    log.error(e.getMessage());
	    throw new RuntimeException(e.getMessage());
	}
    }

    @Override
    public void delete(T t) {
	try {
	    this.getHibernateTemplate().delete(t);
	}
	catch (Exception e) {
	    log.error(e.getMessage());
	    throw new RuntimeException(e.getMessage());
	}
    }

    @Override
    public void deleteAll(Collection<T> entities) {
	try {
	    this.getHibernateTemplate().deleteAll(entities);
	}
	catch (Exception e) {
	    log.error(e.getMessage());
	    throw new RuntimeException(e.getMessage());
	}
    }

    @Override
    public T get(Serializable id) {
	try {
	    return this.getHibernateTemplate().get(entityClass, id);
	}
	catch (Exception e) {
	    log.error(e.getMessage());
	    throw new RuntimeException(e.getMessage());
	}
    }

    @Override
    public List<T> queryAll() {
	try {
	    return this.getHibernateTemplate().find(hqlPrefix);
	}
	catch (Exception e) {
	    log.error(e.getMessage());
	    throw new RuntimeException(e.getMessage());
	}
    }

    @Override
    public List<T> queryToList(Object... paras) {
	try {
	    String hql = setParameters(hqlPrefix, paras);
	    return this.getHibernateTemplate().find(hql);
	}
	catch (IllegalArgumentException e) {
	    log.error(e.getMessage());
	    throw new RuntimeException(e.getMessage());
	}
	catch (Exception e) {
	    log.error(e.getMessage());
	    throw new RuntimeException(e.getMessage());
	}
    }

    /**
     * 可执行一条HQL语句 ，批量模式返回。 注：仅适用查询语句
     * 
     * @param hql HQL语句
     * @return 一批T类型对象，在List里
     */
    protected List<T> queryToList(String hql) {
	try {
	    return this.getHibernateTemplate().find(hql);
	}
	catch (Exception e) {
	    log.error(e.getMessage());
	    throw new RuntimeException(e.getMessage());
	}
    }

    @Override
    public T queryToOne(Object... paras) {
	try {
	    String hql = setParameters(hqlPrefix, paras);
	    List list = this.getHibernateTemplate().find(hql);
	    return uniqueResult(list);
	}
	catch (IllegalArgumentException e) {
	    log.error(e.getMessage());
	    throw new RuntimeException(e.getMessage());
	}
	catch (Exception e) {
	    log.error(e.getMessage());
	    throw new RuntimeException(e.getMessage());
	}
    }

    /**
     * 可执行一条HQL语句 ，单个模式返回。 注：仅适用查询语句
     * 
     * @param hql HQL语句
     * @return 一个T类型的对象
     */
    protected T queryToOne(String hql) {
	try {
	    List list = this.getHibernateTemplate().find(hql);
	    return uniqueResult(list);
	}
	catch (Exception e) {
	    log.error(e.getMessage());
	    throw new RuntimeException(e.getMessage());
	}
    }

    /**
     * 返回列表中的第一条记录结果
     * 
     * @param list 列表
     * @return 单个对象
     */
    private T uniqueResult(List<T> list) {
	int size = list.size();
	if (size == 0) return null;
	if (size > 1) log.warn("单个查询时，在结果中产生多条记录。");
	return list.get(0);
    }

    /**
     * 设置 HQL语句参数
     * 
     * @param hql HQL语句
     * @param paras 参数列表
     * @return 设置完整的HQL语句
     * @throws IllegalArgumentException 参数个数必须为四的倍数
     */
    private String setParameters(String hql, Object... paras) throws IllegalArgumentException {
	if (paras.length % 4 != 0) throw new IllegalArgumentException(
		"参数不正确！必须每四个参数为一组，以属性，关系运算符，值，逻辑连接符，属性，关系运算符，值，逻辑连接符 ……的形式存在。");
	else if (paras.length == 0) return hql;

	// 以上表达式均成立则为语句添加条件 where
	hql += " where";

	/**
	 * 遍历添加HQL语句条件
	 */
	for (int i = 0; i < paras.length; i++) {
	    // 第一项参数被设置
	    hql += " model." + paras[i++];

	    // 第二项参数被设置
	    hql += paras[i++];

	    // 第三项参数被设置
	    paras[i] = "'" + paras[i] + "'";
	    hql += paras[i++];

	    // 若不是最后一个参数
	    if ((i + 1) != paras.length)
	    // 第四项参数被设置
	    hql += paras[i];
	}
	return hql;
    }
}
